package com.hyxt.boot;

import com.hyxt.DTO.PlatConfig;
import com.hyxt.DTO.PlatLinks;
import com.hyxt.api.ILinkService;
import com.hyxt.handler.ServerHandler;
import com.hyxt.handler.TransferHandler;
import com.hyxt.service.IReceiveMsg;
import com.hyxt.utils.Caches;
import com.hyxt.utils.Color;
import com.hyxt.utils.PropretiesUtil;
import com.hyxt.utils.QueryUitl;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.annotation.Resource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * @author songm
 * @version v1.0
 * @Description 数据初始化
 * @Date:2017/12/21
 * @Modifide By:
 **/
@Component()
@Order(value = 1)
public class InitOperation implements CommandLineRunner {
//public class InitOperation {

    @Resource(name = "receiveTransferClientMsg")
    private IReceiveMsg receiveTransferClientMsg;

    @Resource(name = "receive809ServerMsg")
    private IReceiveMsg receive809ServerMsg;

    @Resource(name = "transferHandler")
    private TransferHandler transferHandler;


    @Autowired
    private ILinkService linkService ;
    //平台配置文件
    private static final String propretiesName = "config";

    static Log log = LogFactory.getLog(InitOperation.class);

    @Override
    public void run(String... strings) throws Exception {
//    public void run() throws Exception {

        // jdbc url
        String jdbcUrl = PropretiesUtil.getPropertiesValueUTF8(propretiesName, "jdbc.url");
        // jdbc driver
        String jdbcDriver = PropretiesUtil.getPropertiesValueUTF8(propretiesName, "jdbc.driver");
        // jdbc username
        String jdbcUsername = PropretiesUtil.getPropertiesValueUTF8(propretiesName, "jdbc.username");
        // jdbc password
        String jdbcPassword = PropretiesUtil.getPropertiesValueUTF8(propretiesName, "jdbc.password");

        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName(jdbcDriver);
        ds.setUrl(jdbcUrl);
        ds.setUsername(jdbcUsername);
        ds.setPassword(jdbcPassword);
        ds.setMinIdle(2);
        ds.setMaxTotal(10);
        ds.setMaxConnLifetimeMillis(2000 * 60 * 60);
        QueryUitl.setDataSource(ds);

        parseXML();
        loadVehicleInfo();
    }

    void loadVehicleInfo() {


        //车辆静态信息,平台信息
        QueryRunner qr = QueryUitl.getQueryRunner();
        String sql_str1 = "SELECT CENTERID,ID,M1,IC1,IA1 FROM JTB_PLATINFO";
        //centerID是接入码,id是平台ID
        try {
            Map<String, String> resultMap = qr.query(sql_str1, new ResultSetHandler<Map<String, String>>() {

                @Override
                public Map<String, String> handle(ResultSet rs) throws SQLException {

                    Map<String, String> tmpMap = new HashMap<String, String>();
                    int count = 0;
                    while (rs.next()) {
                        String centerId = rs.getString("CENTERID");
                        String ID = rs.getString("ID");
                        int M1 = rs.getInt("M1");
                        int IA1 = rs.getInt("IA1");
                        int IC1 = rs.getInt("IC1");

                        tmpMap.put(centerId, ID);
                        Caches.accessCodeToM1IA1IC1Cache.put(centerId, new int[]{M1, IA1, IC1});
                        System.out.println("Load平台数据...." + ++count);
                    }
                    return tmpMap;
                }
            });
            System.out.println(resultMap);
            // 装载到本地缓存
            Caches.accessCodeToBusinessCache.putAll(resultMap);
            String sql_str2 = "SELECT V.ID_NUMBER,V.COLOR_ID_NUMBER_ID,P.PID FROM V_VEHICLEINFO V INNER JOIN  JTB_PLAT_VEHICLE P ON V.VEHICLE_ID=P.VID where V.VEHICLE_ID in ( select vid from v_vehicleinfo_up )";
            Map<String, List<Integer>> plateMap = qr.query(sql_str2, new ResultSetHandler<Map<String, List<Integer>>>() {
                @Override
                public Map<String, List<Integer>> handle(ResultSet rs) throws SQLException {
                    Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();
                    int count = 0;
                    while (rs.next()) {
                        try {

                            String id_Number = rs.getString("ID_NUMBER");
                            String color = rs.getString("COLOR_ID_NUMBER_ID");
                            //部标颜色和系统颜色的转化
                            color = Color.conColor(color);
                            int pid = rs.getInt("PID");
                            String key = id_Number + color;
                            if (map.containsKey(key)) {
                                // 有这个key
                                map.get(key).add(pid);
                            } else {
                                List<Integer> list = new ArrayList<Integer>();
                                list.add(pid);
                                map.put(key, list);
                            }
                            log.info("Load车辆数据.... key " + key + " to " + map.get(key));
                        } catch (Exception e) {
                            log.warn("", e);
                        }
                        // System.out.println();
                    }
                    return map;
                }
            });
            // 装载本地缓存
            Caches.plateToBusinessCache.putAll(plateMap);

        } catch (SQLException e) {
            e.printStackTrace();
            System.exit(0);
        }

    }

    /**
     * 读取平台配置文件
     */
    void parseXML() {
        //创建一个DocumentBuilderFactory的对象
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            //创建DocumentBuilder对象
            DocumentBuilder db = dbf.newDocumentBuilder();

            //通过DocumentBuilder对象的parser方法加载platConfig.xml文件到当前项目下
            //传入文件名可以是相对路径也可以是绝对路径
            Document document = db.parse("classpath:platConfig.xml");
            //获取所有plat节点的集合
            NodeList platList = document.getElementsByTagName("plat");

            //遍历每一个平台节点
            for (int i = 0; i < platList.getLength(); i++) {
                PlatConfig platConfig = new PlatConfig();
                //将节点进行强制类型转换，转换成Element类型
                Element plat = (Element) platList.item(i);
                //通过getAttribute方法获取属性值
                String platId = plat.getAttribute("platId");
                platConfig.setPlatId(platId);
                System.out.println("平台id:" + platId);
                //获取接入码
                Element acElement = (Element) plat.getElementsByTagName("acceptCode").item(0);
                String acceptCode = acElement.getAttribute("value");
                platConfig.setAcceptCode(acceptCode);
                //获取白名单
                Element wlElement = (Element) plat.getElementsByTagName("whiteList").item(0);
                String whiteList = acElement.getAttribute("value");
                platConfig.setWhiteList(whiteList);
                //获取主链路端口
                Element mcpElement = (Element) plat.getElementsByTagName("mainChannelPort").item(0);
                String mainChannelPort = acElement.getAttribute("value");
                platConfig.setMainLinkPort(Integer.parseInt(mainChannelPort));
                //获取从链路ip
                Element sciElement = (Element) plat.getElementsByTagName("subChannelIp").item(0);
                String subChannelIp = sciElement.getAttribute("value");
                platConfig.setSlaveLinkIp(subChannelIp);
                //获取从链路port
                Element scpElement = (Element) plat.getElementsByTagName("subChannelPort").item(0);
                String subChannelPort = scpElement.getAttribute("value");
                platConfig.setSlaveLinkPort(Integer.parseInt(subChannelPort));
                //获取转发链路ip
                Element tciElement = (Element) plat.getElementsByTagName("transferChannelIp").item(0);
                String transferChannelIp = tciElement.getAttribute("value");
                platConfig.setTransferLinkIp(transferChannelIp);
                //获取转发链路port
                Element tcpElement = (Element) plat.getElementsByTagName("transferChannelPort").item(0);
                String transferChannelPort = tcpElement.getAttribute("value");
                platConfig.setTransferLinkPort(Integer.parseInt(transferChannelPort));
                //获取运管ip
                Element tpiElement = (Element) plat.getElementsByTagName("transportChannelIp").item(0);
                String transportChannelIp = tpiElement.getAttribute("value");
                platConfig.setTransportMgtIp(transportChannelIp);
                //获取运管port
                Element tppElement = (Element) plat.getElementsByTagName("transportChannelPort").item(0);
                String transportChannelPort = tppElement.getAttribute("value");
                platConfig.setTransportMgtPort(Integer.parseInt(transportChannelPort));

                //将平台连接状态存入缓存（空对象）
                PlatLinks platLinks = new PlatLinks();
                Caches.platLinks.put(platId, platLinks);

                //将平台配置信息存入缓存
                Caches.platConfigs.put(platId, platConfig);

                String mainChannel = linkService.start(platId, Integer.parseInt(mainChannelPort));
                //主链服务端开启成功
                if (mainChannel != null) {
                    //服务端开启不代表主链路创建成功
                    //等待客户端调用Receive809ServerMsg时说明主链路创建成功
                    //在调用的时候设置handler的mainChannel
                    ServerHandler serverHandler = new ServerHandler();
                    serverHandler.setPlatConfig(platConfig);
                    serverHandler.setPlatId(platId);
                    //每条主链路都对应一个handler
                    Caches.serverHandlers.put(mainChannel, serverHandler);
                    //开始监听通道的消息
                    receive809ServerMsg.listen(mainChannel);
                }

                //转发链路连接交通部成功
                connectTransfer(platConfig);

            }

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接交通部转发链路
     *
     * @param platConfig
     * @return 连接成功返回channelName，否则返回null
     */
    void connectTransfer(final PlatConfig platConfig) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                try {
                    final String channelName = linkService.connectTOM(platConfig.getPlatId(), platConfig.getTransferLinkIp(), platConfig.getTransferLinkPort());
                    System.out.println("重连。。。");
                    //首次与交通部链路建立成功后发上行认证
                    if (channelName != null && Caches.transferHandlers.get(channelName) == null) {
//                        TransferHandler transferHandler = new TransferHandler();
                        transferHandler.setPlatConfig(platConfig);
                        transferHandler.setPlatId(platConfig.getPlatId());
                        Caches.transferHandlers.put(channelName, transferHandler);
                        PlatLinks platLinks = (PlatLinks) Caches.platLinks.get(platConfig.getPlatId());
                        platLinks.setTransferChannel(channelName);
                        //连接成功后调用转发链路监听接口
                        if (receiveTransferClientMsg.listen(channelName)) {
                            //发送上行认证消息
                            transferHandler.UplinkAuthentication(platConfig.getAcceptCode());
                        } else {
                            //如果调用失败则重试3次
                            try {
                                Thread.sleep(1000);
                                for (int j = 0; j < 4; j++) {
                                    if (receiveTransferClientMsg.listen(channelName)) {
                                        //发送上行认证消息
                                        transferHandler.UplinkAuthentication(platConfig.getAcceptCode());
                                        break;
                                    }
                                }
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                log.error("调用ReceiveTransferClientMsg接口重试3次失败：" + e.getMessage());
                            }
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 10 * 1000, 10 * 1000);


    }

}
